/* http://keith-wood.name/svg.html
   SVG attribute animations for jQuery v1.1.1.
   Written by Keith Wood (kbwood@virginbroadband.com.au) June 2008.
   Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and 
   MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses. 
   Please attribute the author if you use it. */

 (function($) { // Hide scope, no $ conflict

	// Enable animation for all of these SVG numeric properties
	$.each(['x', 'y', 'width', 'height', 'rx', 'ry', 'cx', 'cy', 'r', 'x1', 'y1', 'x2', 'y2',
			'stroke-width', 'opacity', 'fill-opacity', 'stroke-opacity', 'font-size'],
		function(i, attrName) {
			$.fx.step['svg-' + attrName] = function(fx) {
				var attr = fx.elem.attributes.getNamedItem(attrName);
				if (fx.state == 0) {
					fx.start = (attr ? parseFloat(attr.nodeValue) : 0);
					var offset = fx.options.curAnim['svg-' + attrName];
					if (/^[+-]=/.exec(offset)) {
						fx.end = fx.start + parseFloat(offset.replace(/=/, ''));
				}
				}
				var value = (fx.pos * (fx.end - fx.start) + fx.start) + (fx.unit == '%' ? '%' : '');
				(attr ? attr.nodeValue = value : fx.elem.setAttribute(attrName, value));
			};
		}
	);

	// Enable animation for the SVG transform property
	$.fx.step['svg-transform'] = function(fx) {
		var attr = fx.elem.attributes.getNamedItem('transform');
		if (fx.state == 0) {
			fx.start = parseTransform(attr ? attr.nodeValue : '');
			fx.end = parseTransform(fx.end, fx.start);
		}
		var transform = '';
		for (var i = 0; i < fx.end.order.length; i++) {
			switch (fx.end.order.charAt(i)) {
				case 't':
					transform += (fx.start.translateX != fx.end.translateX || fx.start.translateY != fx.end.translateY ?
			' translate(' + (fx.pos * (fx.end.translateX - fx.start.translateX) + fx.start.translateX) + ',' +
						(fx.pos * (fx.end.translateY - fx.start.translateY) + fx.start.translateY) + ')' : '');
					break;
				case 's':
					transform += (fx.start.scaleX != fx.end.scaleX || fx.start.scaleY != fx.end.scaleY ? 
			' scale(' + (fx.pos * (fx.end.scaleX - fx.start.scaleX) + fx.start.scaleX) + ',' +
						(fx.pos * (fx.end.scaleY - fx.start.scaleY) + fx.start.scaleY) + ')' : '');
					break;
				case 'r':
					transform += (fx.start.rotateA != fx.end.rotateA ||
			fx.start.rotateX != fx.end.rotateX || fx.start.rotateY != fx.end.rotateY ? 
			' rotate(' + (fx.pos * (fx.end.rotateA - fx.start.rotateA) + fx.start.rotateA) + ',' +
			(fx.pos * (fx.end.rotateX - fx.start.rotateX) + fx.start.rotateX) + ',' +
						(fx.pos * (fx.end.rotateY - fx.start.rotateY) + fx.start.rotateY) + ')' : '');
					break;
				case 'x':
					transform += (fx.start.skewX != fx.end.skewX ? 
						' skewX(' + (fx.pos * (fx.end.skewX - fx.start.skewX) + fx.start.skewX) + ')' : '');
				case 'y':
					transform += (fx.start.skewY != fx.end.skewY ? 
			' skewY(' + (fx.pos * (fx.end.skewY - fx.start.skewY) + fx.start.skewY) + ')' : '');
					break;
			}
		}
		(attr ? attr.nodeValue = transform : fx.elem.setAttribute('transform', transform));
	};
	
	// Decode a transform string and extract component values
	function parseTransform(value, original) {
		value = value || '';
		if (typeof value == 'object') {
			value = value.nodeValue;
		}
		var transform = $.extend({translateX: 0, translateY: 0, scaleX: 0, scaleY: 0,
			rotateA: 0, rotateX: 0, rotateY: 0, skewX: 0, skewY: 0}, original || {});
		transform.order = '';
		var pattern = /([a-zA-Z]+)\(\s*([+-]?[\d\.]+)\s*,?\s*([+-]?[\d\.]+)?\s*,?\s*([+-]?[\d\.]+)?\s*\)/g;
		var result = pattern.exec(value);
		while (result) {
			switch (result[1]) {
				case 'translate':
					transform.order += 't';
					transform.translateX = parseFloat(result[2]);
					transform.translateY = (result[3] ? parseFloat(result[3]) : 0);
					break;
				case 'scale':
					transform.order += 's';
					transform.scaleX = parseFloat(result[2]);
					transform.scaleY = (result[3] ? parseFloat(result[3]) : result[1]);
					break;
				case 'rotate':
					transform.order += 'r';
					transform.rotateA = parseFloat(result[2]);
					transform.rotateX = (result[3] ? parseFloat(result[3]) : 0);
					transform.rotateY = (result[4] ? parseFloat(result[4]) : 0);
					break;
				case 'skewX':
					transform.order += 'x';
					transform.skewX = parseFloat(result[2]);
					break;
				case 'skewY':
					transform.order += 'y';
					transform.skewY = parseFloat(result[2]);
					break;
		}
			result = pattern.exec(value);
		}
		return transform;
	}

	// Enable animation for all of these SVG colour properties - based on jquery.color.js
	$.each(['fill', 'stroke'],
		function(i, attrName) {
			$.fx.step['svg-' + attrName] = function(fx) {
				if (fx.state == 0) {
					fx.start = getColour(fx.elem, attrName);
					var toNone = (fx.end == 'none');
					fx.end = (toNone ? getColour(fx.elem.parentNode, attrName) : getRGB(fx.end));
					fx.end[3] = toNone;
				}
				var attr = fx.elem.attributes.getNamedItem(attrName);
				var colour = 'rgb(' + [
					Math.min(Math.max(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 0), 255),
					Math.min(Math.max(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 0), 255),
					Math.min(Math.max(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 0), 255)
				].join(',') + ')';
				colour = (fx.end[3] && fx.state == 1 ? 'none' : colour);
				(attr ? attr.nodeValue = colour : fx.elem.setAttribute(attrName, colour));
			}
		}
	);
	
	// Find this attribute value somewhere up the node hierarchy
	function getColour(elem, attr) {
		var colour;
		do {
			colour = (elem.attributes && elem.attributes.getNamedItem(attr) ?
				elem.attributes.getNamedItem(attr).nodeValue : '');
			// Keep going until we find an element that has colour, or exit SVG
			if ((colour != '' && colour != 'none') || $(elem).is('.hasSVG')) {
				break; 
			}
		} while (elem = elem.parentNode);
		return getRGB(colour);
	}

	// Parse strings looking for common colour formats
	function getRGB(colour) {
		var result;
		// Check if we're already dealing with an array of colors
		if (colour && colour.constructor == Array && (colour.length == 3 || colour.length == 4)) {
			return colour;
		}
		// Look for rgb(num,num,num)
		if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(colour)) {
			return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];
		}
		// Look for rgb(num%,num%,num%)
		if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(colour)) {
			return [parseFloat(result[1]) * 2.55, parseFloat(result[2]) * 2.55,
				parseFloat(result[3]) * 2.55];
		}
		// Look for #a0b1c2
		if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(colour)) {
			return [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)];
		}
		// Look for #fff
		if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(colour)) {
			return [parseInt(result[1] + result[1], 16), parseInt(result[2] + result[2], 16),
				parseInt(result[3] + result[3], 16)];
		}
		// Otherwise, we're most likely dealing with a named color
		return colours[$.trim(colour).toLowerCase()] || colours['none'];
	}
	
	// The SVG named colours
	var colours = {
		'':						[255, 255, 255, 1],
		none:					[255, 255, 255, 1],
		aliceblue:				[240, 248, 255],
		antiquewhite:			[250, 235, 215],
		aqua:					[ 0, 255, 255],
		aquamarine:				[127, 255, 212],
		azure:					[240, 255, 255],
		beige:					[245, 245, 220],
		bisque:					[255, 228, 196],
		black:					[ 0, 0, 0],
		blanchedalmond:			[255, 235, 205],
		blue:					[ 0, 0, 255],
		blueviolet:				[138, 43, 226],
		brown:					[165, 42, 42],
		burlywood:				[222, 184, 135],
		cadetblue:				[ 95, 158, 160],
		chartreuse:				[127, 255, 0],
		chocolate:				[210, 105, 30],
		coral:					[255, 127, 80],
		cornflowerblue:			[100, 149, 237],
		cornsilk:				[255, 248, 220],
		crimson:				[220, 20, 60],
		cyan:					[ 0, 255, 255],
		darkblue:				[ 0, 0, 139],
		darkcyan:				[ 0, 139, 139],
		darkgoldenrod:			[184, 134, 11],
		darkgray:				[169, 169, 169],
		darkgreen:				[ 0, 100, 0],
		darkgrey:				[169, 169, 169],
		darkkhaki:				[189, 183, 107],
		darkmagenta:			[139, 0, 139],
		darkolivegreen:			[ 85, 107, 47],
		darkorange:				[255, 140, 0],
		darkorchid:				[153, 50, 204],
		darkred:				[139, 0, 0],
		darksalmon:				[233, 150, 122],
		darkseagreen:			[143, 188, 143],
		darkslateblue:			[ 72, 61, 139],
		darkslategray:			[ 47, 79, 79],
		darkslategrey:			[ 47, 79, 79],
		darkturquoise:			[ 0, 206, 209],
		darkviolet:				[148, 0, 211],
		deeppink:				[255, 20, 147],
		deepskyblue:			[ 0, 191, 255],
		dimgray:				[105, 105, 105],
		dimgrey:				[105, 105, 105],
		dodgerblue:				[ 30, 144, 255],
		firebrick:				[178, 34, 34],
		floralwhite:			[255, 250, 240],
		forestgreen:			[ 34, 139, 34],
		fuchsia:				[255, 0, 255],
		gainsboro:				[220, 220, 220],
		ghostwhite:				[248, 248, 255],
		gold:					[255, 215, 0],
		goldenrod:				[218, 165, 32],
		gray:					[128, 128, 128],
		grey:					[128, 128, 128],
		green:					[ 0, 128, 0],
		greenyellow:			[173, 255, 47],
		honeydew:				[240, 255, 240],
		hotpink:				[255, 105, 180],
		indianred:				[205, 92, 92],
		indigo:					[ 75, 0, 130],
		ivory:					[255, 255, 240],
		khaki:					[240, 230, 140],
		lavender:				[230, 230, 250],
		lavenderblush:			[255, 240, 245],
		lawngreen:				[124, 252, 0],
		lemonchiffon:			[255, 250, 205],
		lightblue:				[173, 216, 230],
		lightcoral:				[240, 128, 128],
		lightcyan:				[224, 255, 255],
		lightgoldenrodyellow:	[250, 250, 210],
		lightgray:				[211, 211, 211],
		lightgreen:				[144, 238, 144],
		lightgrey:				[211, 211, 211],
		lightpink:				[255, 182, 193],
		lightsalmon:			[255, 160, 122],
		lightseagreen:			[ 32, 178, 170],
		lightskyblue:			[135, 206, 250],
		lightslategray:			[119, 136, 153],
		lightslategrey:			[119, 136, 153],
		lightsteelblue:			[176, 196, 222],
		lightyellow:			[255, 255, 224],
		lime:					[ 0, 255, 0],
		limegreen:				[ 50, 205, 50],
		linen:					[250, 240, 230],
		magenta:				[255, 0, 255],
		maroon:					[128, 0, 0],
		mediumaquamarine:		[102, 205, 170],
		mediumblue:				[ 0, 0, 205],
		mediumorchid:			[186, 85, 211],
		mediumpurple:			[147, 112, 219],
		mediumseagreen:			[ 60, 179, 113],
		mediumslateblue:		[123, 104, 238],
		mediumspringgreen:		[ 0, 250, 154],
		mediumturquoise:		[ 72, 209, 204],
		mediumvioletred:		[199, 21, 133],
		midnightblue:			[ 25, 25, 112],
		mintcream:				[245, 255, 250],
		mistyrose:				[255, 228, 225],
		moccasin:				[255, 228, 181],
		navajowhite:			[255, 222, 173],
		navy:					[ 0, 0, 128],
		oldlace:				[253, 245, 230],
		olive:					[128, 128, 0],
		olivedrab:				[107, 142, 35],
		orange:					[255, 165, 0],
		orangered:				[255, 69, 0],
		orchid:					[218, 112, 214],
		palegoldenrod:			[238, 232, 170],
		palegreen:				[152, 251, 152],
		paleturquoise:			[175, 238, 238],
		palevioletred:			[219, 112, 147],
		papayawhip:				[255, 239, 213],
		peachpuff:				[255, 218, 185],
		peru:					[205, 133, 63],
		pink:					[255, 192, 203],
		plum:					[221, 160, 221],
		powderblue:				[176, 224, 230],
		purple:					[128, 0, 128],
		red:					[255, 0, 0],
		rosybrown:				[188, 143, 143],
		royalblue:				[ 65, 105, 225],
		saddlebrown:			[139, 69, 19],
		salmon:					[250, 128, 114],
		sandybrown:				[244, 164, 96],
		seagreen:				[ 46, 139, 87],
		seashell:				[255, 245, 238],
		sienna:					[160, 82, 45],
		silver:					[192, 192, 192],
		skyblue:				[135, 206, 235],
		slateblue:				[106, 90, 205],
		slategray:				[112, 128, 144],
		slategrey:				[112, 128, 144],
		snow:					[255, 250, 250],
		springgreen:			[ 0, 255, 127],
		steelblue:				[ 70, 130, 180],
		tan:					[210, 180, 140],
		teal:					[ 0, 128, 128],
		thistle:				[216, 191, 216],
		tomato:					[255, 99, 71],
		turquoise:				[ 64, 224, 208],
		violet:					[238, 130, 238],
		wheat:					[245, 222, 179],
		white:					[255, 255, 255],
		whitesmoke:				[245, 245, 245],
		yellow:					[255, 255, 0],
		yellowgreen:			[154, 205, 50]
	};
})(jQuery);
